# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
from datetime import datetime
import pathlib
from jqdatasdk import auth, bond, query, get_price, normalize_code
from tqdm import tqdm
import requests
import io
import time
import json
from typing import List


def refresh_conbond(cache_dir: pathlib.Path, username=None, password=None):
    if username is not None:
        auth(username, password)
    count = 0

    # conbond_basic_info
    fbasic_info = cache_dir.joinpath('conbond_basic_info.csv')
    if fbasic_info.exists():
        df_basic_info = pd.read_csv(fbasic_info, index_col=['code'])
    else:
        print('Read conbond_basic_info from jqdata')
        df_basic_info = bond.run_query(query(bond.CONBOND_BASIC_INFO))
        df_basic_info.set_index('code')
        df_basic_info.to_csv(fbasic_info)

    # conbond_convert_price_adjust
    fconvert_price_adjust = cache_dir.joinpath(
        'conbond_convert_price_adjust.csv')
    if fconvert_price_adjust.exists():
        df_convert_price_adjust = pd.read_csv(fconvert_price_adjust)
    else:
        print('Read conbond_convert_price_adjust from jqdata')
        df_convert_price_adjust = bond.run_query(
            query(bond.CONBOND_CONVERT_PRICE_ADJUST))
        assert (len(df_convert_price_adjust) < 5000)
        df_convert_price_adjust.to_csv(fconvert_price_adjust, index=False)

    for idx in tqdm(df_basic_info.index.tolist()):
        conbond = df_basic_info.loc[idx]
        # For some reason some company_code is nan
        if pd.isna(conbond.company_code):
            continue

        # conbond_daily_price
        fbond_price = cache_dir.joinpath('%s.csv' % idx)
        if fbond_price.exists():
            df_bond_price = pd.read_csv(fbond_price)
        else:
            count += 1
            df_bond_price = bond.run_query(
                query(bond.CONBOND_DAILY_PRICE).filter(
                    bond.CONBOND_DAILY_PRICE.code == idx))
            assert (len(df_bond_price) < 5000)
            if len(df_bond_price) == 0:
                print('No price for %s' % idx)
                continue
            df_bond_price.to_csv(fbond_price, index=False)

        # conbond_daily_convert
        fbond_convert = cache_dir.joinpath('%s_convert.csv' % idx)
        if fbond_convert.exists():
            df_bond_convert = pd.read_csv(fbond_convert)
        else:
            count += 1
            df_bond_convert = bond.run_query(
                query(bond.CONBOND_DAILY_CONVERT).filter(
                    bond.CONBOND_DAILY_CONVERT.code == idx))
            assert (len(df_bond_convert) < 5000)
            df_bond_convert.to_csv(fbond_convert, index=False)

        # stock_daily_price
        fstock_price = cache_dir.joinpath('%s.csv' % conbond.company_code)
        if fstock_price.exists():
            df_stock_price = pd.read_csv(fstock_price)
        else:
            count += 1
            df_stock_price = get_price(conbond.company_code,
                                       start_date=conbond.list_date,
                                       end_date=datetime.now().date(),
                                       frequency='daily',
                                       fq=None,
                                       panel=False)
            df_stock_price['code'] = conbond.company_code
            df_stock_price.reset_index(inplace=True)
            df_stock_price.rename(columns={'index': 'date'}, inplace=True)
            df_stock_price.to_csv(fstock_price, index=False)

            #  url = 'https://dataapi.joinquant.com/apis'
            #  body = {
            #  'method': 'get_price_period',
            #  'token': '5b6a9baab5f17fb76c2b782d07c50dbba814d3',
            #  'code': conbond.company_code,
            #  'date': conbond.list_date,
            #  'unit': '1d',
            #  }
            #  response = requests.post(url, data=json.dumps(body))
            #  df_stock_price = pd.read_csv(io.StringIO(response.text))
            #  df_stock_price['code'] = conbond.company_code
            #  df_stock_price.to_csv(fstock_price, index=False)

    print('Read conbond / stock price from jqdata: %s' % count)


def combine_conbond(cache_dir: pathlib.Path):
    fconbonds = cache_dir.joinpath('conbonds.csv')
    fbasic_info = cache_dir.joinpath('conbond_basic_info.csv')
    df_basic_info = pd.read_csv(fbasic_info, index_col=['code'])
    df_basic_info.fillna({'delist_Date': '0000-00-00'}, inplace=True)
    df_basic_info.fillna({'list_date': '0000-00-00'}, inplace=True)
    df_basic_info = df_basic_info[df_basic_info.delist_Date.apply(
        lambda d: pd.isna(d) or str(d) > '2018-01-01')]

    conbonds = []
    for idx in tqdm(df_basic_info.index.tolist()):
        conbond = df_basic_info.loc[idx]
        # For some reason some company_code is nan
        if pd.isna(conbond.company_code):
            continue

        fbond_price = cache_dir.joinpath('%s.csv' % idx)
        df_bond_price = pd.read_csv(fbond_price, indexcol=['date'])
        assert not df_bond_price.empty
        df_conbond = df_bond_price[['open', 'close', 'pre_close',
                                    'volume']].copy()
        #  if conbond.delist_Date != '0000-00-00':
        #  128012.XSHE, delisted in 2021-04-20, only has price until 2020-05-22
        #  assert df_conbond.date.max() == conbond.delist_Date

        fbond_convert = cache_dir.joinpath('%s_convert.csv' % conbond.code)
        df_bond_convert = pd.read_csv(fbond_convert, index_col=['date'])
        if df_bond_convert.empty():
            df_conbond['convert_price'] = np.nan
            df_conbond.fillna({'convert_price': conbond.convert_price},
                              inplace=True)
        else:
            df_conbond = df_conbond.join(df_bond_convert['convert_price'])

        fstock_price = cache_dir.joinpath('%s.csv' % conbond.company_code)
        df_stock_price = pd.read_csv(fstock_price, index_col=['date'])
        df_stock_price.rename(columns={'open': 'stock_open'}, inplace=True)

        df_conbond = df_conbond.join(df_stock_price)
        df_conbond['convert_premium_rate'] = df_conbond.open / (
            100 / df_conbond.convert_price * df_conbond.stock_open) - 1

        df_conbond.reset_index(inplace=True)
        df_conbond['order_book_id'] = normalize_code(idx)
        df_conbond.rename(columns={'date': 'datetime'}, inplace=True)
        conbonds.append(df_conbond)

    print('Create combined conbond data: %s' % len(conbonds))
    df_conbonds = pd.concat(conbonds)
    df_conbonds['suspended'] = df_conbonds.apply(lambda cb: not cb.open > 0)
    df_conbonds.to_csv(fconbonds, index=False)

    gen_all_instruments(cache_dir, df_basic_info)
    return df_conbonds


def gen_all_instruments(cache_dir: pathlib.Path, df: pd.DataFrame):
    f_all_instruments = cache_dir.joinpath('all_instruments.csv')
    print('Create all_instruments')
    df = df[df.bond_type_id == 703013]

    df = df[['short_name', 'list_date', 'delist_Date',
             'list_status_id']].rename(
                 columns={
                     'short_name': 'symbol',
                     'list_date': 'listed_date',
                     'delist_Date': 'de_listed_date',
                 })
    df['order_book_id'] = df.index.astype(str).apply(
        lambda c: normalize_code(c))
    df['trading_hours'] = '09:31-11:30,13:01-15:00'
    df['board_type'] = 'MainBoard'
    df['type'] = 'CS'
    df['market_tplus'] = 0
    df['status'] = df.list_status_id.apply(lambda d: 'Delisted'
                                           if d == 301006 else 'Active')
    df['round_lot'] = 10
    df['account_type'] = 'STOCK'
    df.to_csv(f_all_instruments, index=False)


def refresh_misc(cache_dir: pathlib.Path,
                 instruments: List[str] = [],
                 username=None,
                 password=None):
    if username is not None:
        auth(username, password)
    count = 0

    for idx in tqdm(range(len(instruments))):
        order_book_id = normalize_code(instruments[idx])
        finstrument = cache_dir.joinpath('%s.csv' % order_book_id)
        if not finstrument.exists():
            count += 1
            df_instrument = get_price(order_book_id,
                                      start_date='2018-01-01',
                                      end_date=datetime.now().date(),
                                      frequency='daily',
                                      fq=None,
                                      panel=False)
            df_instrument.reset_index(inplace=True)
            df_instrument.rename(columns={'index': 'date'}, inplace=True)
            df_instrument.to_csv(finstrument, index=False)
    print('Read stock price from jqdata: %s' % count)
